package gogsci

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync/atomic"
	"time"
)

var (
	scriptPath string = "./scripts"
)

type Queue struct {
	listChan     chan *PushPayload
	MaxQueueSize int64
	stop         chan struct{}

	Handler      QueueHandler
	ExecNum      int64 // 正在执行的数量.
	WaitDuration time.Duration
}

func (q *Queue) Push(payload *PushPayload) {
	q.listChan <- payload
}

func (q *Queue) Start(store Store) {
	for {
		select {
		case pp := <-q.listChan:
			for {
				if q.MaxQueueSize != 0 && atomic.LoadInt64(&q.ExecNum) >= q.MaxQueueSize {
					time.Sleep(q.WaitDuration)
					continue
				}

				atomic.AddInt64(&q.ExecNum, 1)
				go func() {
					defer atomic.AddInt64(&q.ExecNum, -1)
					res, err := q.Handler(pp)
					if err != nil {
						logger.WithError(err).Infof(`exec pushPayload failed: name: %s commit:%s`, pp.Repo.FullName, pp.Before)
						return
					}
					store.SaveResult(pp, res)
				}()
				break
			}
		case <-q.stop:
			return
		}
	}
}

func (q *Queue) Stop() {
	q.stop <- struct{}{}
}

func NewQueue(chanSize int, maxQueueSize int64, handler QueueHandler, store Store) *Queue {
	q := new(Queue)
	q.listChan = make(chan *PushPayload, chanSize)
	if maxQueueSize > 0 {
		q.MaxQueueSize = maxQueueSize
	} else {
		q.MaxQueueSize = 10
	}
	if handler != nil {
		q.Handler = handler
	} else {
		q.Handler = DefaultQueueHandler
	}

	go q.Start(store)
	return q
}

type QueueHandler func(payload *PushPayload) (*Result, error)

func DefaultQueueHandler(payload *PushPayload) (res *Result, err error) {

	env := NewEnvironment(payload)

	// fetch 拉代码.
	msg := ExecuteScript(filepath.Join(scriptPath, "fetch.sh"), env)
	fmt.Println(msg)

	// 获取CI文件.
	cipath := filepath.Join(env[REPO_FULL_PATH], CI_FILE)

	b, err := ioutil.ReadFile(cipath)

	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}

		return nil, err
	}

	ci, err := NewCi(b, payload)
	if err != nil {
		logger.WithError(err).Info(`parse ci file failed`)
		return nil, err
	}

	err = ci.Run(env)

	_ = msg
	return
}
